package think.in.spring.bean;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import think.in.spring.config.HierarchicalDemoConfig;

import java.util.Map;

/**
 * + 层次性查找
 *   + 根据Bean名称查找
 *     + 基于containsLocalBean方法实现
 *   + 根据Bean类型查找实例列表
 *     + 单一类型
 *       BeanFactoryUtils#beanOfType
 *     + 集合类型
 *       BeanFactoryUtils#beansOfTypeIncludingAncestors
 *     + 根据Java注解查找名称列表
 *       BeanFactoryUtils#beanNamesForTypeIncludingAncestors
 *       如果父子上下文中有名称一样的Bean，只会返回子上下文
 */
public class HierarchicalDependencyLookupDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(HierarchicalDemoConfig.SubLayerConfig.class);
        context.refresh();
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        addParentContext(beanFactory);
        HierarchicalBeanFactory parentBeanFactory = (HierarchicalBeanFactory)beanFactory.getParentBeanFactory();
        System.out.println("parentBeanFactory"+parentBeanFactory);
        System.out.println("containsLocalBean_sublayer1:"+beanFactory.containsLocalBean("sublayer1"));
        System.out.println("containsLocalBean_layer2:"+beanFactory.containsLocalBean("layer2"));
        System.out.println("containsLocalBean_layer2:"+parentBeanFactory.containsLocalBean("layer2"));
        Object parentBean = parentBeanFactory.getBean("forTest");
        System.out.println("父子有相同Bean场景:"+parentBean);

        Object subTest = beanFactory.getBean("forTest");
        System.out.println("父子有相同Bean场景:"+subTest);

        Map<String, String> beanMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, String.class);
        System.out.println("beansOfTypeIncludingAncestors:"+beanMap);

        System.out.println("containBeanName-beanFactory:"+containBeanName(beanFactory, "forTest"));
        System.out.println("containBeanName-beanFactory:"+containBeanName(parentBeanFactory, "forTest"));
        System.out.println("containBeanName-beanFactory:"+containBeanName(beanFactory, "layer2"));
        context.close();
    }

    private static void addParentContext(ConfigurableListableBeanFactory beanFactory) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(HierarchicalDemoConfig.class);
        context.refresh();
        beanFactory.setParentBeanFactory(context.getBeanFactory());
    }

    /**
     * 递归查询上下文有beanName
     * @param hierarchicalBeanFactory
     * @param beanName
     * @return
     */
    public static boolean containBeanName(HierarchicalBeanFactory hierarchicalBeanFactory,String beanName) {
        if(hierarchicalBeanFactory.containsLocalBean(beanName)) {
            return true;
        }else{
            BeanFactory parentBeanFactory = hierarchicalBeanFactory.getParentBeanFactory();
            if(parentBeanFactory instanceof  HierarchicalBeanFactory) {
                parentBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);
                return containBeanName((HierarchicalBeanFactory)parentBeanFactory,beanName);
            }
        }
        return false;
    }
}
